package pl.gettoknowme.mobile.android.integration;

import java.util.List;
import java.util.Map;

import pl.gettoknowme.mobile.android.model.DBAdapter;
import pl.gettoknowme.mobile.android.model.dbtypes.Integration;
import pl.gettoknowme.mobile.android.model.dbtypes.Integration.IntegrationType;
import pl.gettoknowme.mobile.android.network.NetworkException;
import pl.gettoknowme.mobile.android.network.NetworkManager;
import pl.gettoknowme.mobile.android.network.request.impl.CallsStatsHttpRequestWrapper;
import pl.gettoknowme.mobile.android.network.response.HttpResponseWrapper;
import pl.gettoknowme.mobile.android.services.calls.CallLogAnalyzer;
import pl.gettoknowme.mobile.android.services.calls.CallLogEntry;
import pl.gettoknowme.mobile.android.services.calls.CallLogReader;
import pl.gettoknowme.mobile.android.services.calls.CallSingleNumberStats;
import pl.gettoknowme.mobile.android.services.calls.CallLogEntry.CallType;
import pl.gettoknowme.mobile.android.util.LoggingUtil;
import android.content.Context;

/**
 * Implementacja wykonania wątku integracji statystyk połączeń telefonicznych
 * @author Michał Kołodziejski
 */
public class CallsStatsIntegrationRunnable implements Runnable {
    
    protected Context context;
    protected String userId;
    protected Long lastIntegrationTimestamp;
    protected long nowTimestamp;
    
    public CallsStatsIntegrationRunnable(Context context, String userId, Long lastIntegrationTimestamp) {
        this.context = context;
        this.userId = userId;
        this.lastIntegrationTimestamp = lastIntegrationTimestamp;
    }

    @Override
    public void run() {
        // wczytanie logów połączeń
        Map<CallType, List<CallLogEntry>> callLogs = getCallLogs();
        nowTimestamp = System.currentTimeMillis();
        
        // analiza połączeń
        List<CallSingleNumberStats> analyzedCallLogs = getGroupedByNumberTotalCallTimes(callLogs);
        
        // wysłanie
        DBAdapter dbAdapter = DBAdapter.getInstance(context);
        Integration integration = new Integration();
        integration.setIntegrationTime(nowTimestamp);
        integration.setIntegrationType(IntegrationType.CALLS_STATS);
        if(sendAPIRequest(analyzedCallLogs)){
            LoggingUtil.d(this, "API request finished successfully");
            
            // zakończone powodzeniem - zapisujemy info o udanej integracji
            integration.setSuccessful(true);
            dbAdapter.getIntegrationDAO().insert(integration);
            
        } else {
            // zakończone niepowodzeniem - zapisujemy info o udanej integracji
            integration.setSuccessful(false);
            dbAdapter.getIntegrationDAO().insert(integration);
        }
        
    }

    
    /**
     * Zwraca mapę z danymi połączeń telefonicznych
     * @return mapa: typ_połączenia -> lista logów połączeń
     */
    private Map<CallType, List<CallLogEntry>> getCallLogs(){
        CallLogReader callLogReader = new CallLogReader(context);
        Map<CallType, List<CallLogEntry>> callLogs = null;
        
        if(lastIntegrationTimestamp != null){
            callLogs = callLogReader.readCallLogs(lastIntegrationTimestamp.longValue());
        } else {
            callLogs = callLogReader.readCallLogs();
        }
        
        return callLogs;
    }
    
    
    /**
     * Zwraca statystyki połączeń telefonicznych pogrupowane po numerze telefonu
     * @param callLogs logi połączeń telefonicznych
     * @return lista statystyk połączeń
     */
    private List<CallSingleNumberStats> getGroupedByNumberTotalCallTimes(Map<CallType, List<CallLogEntry>> callLogs){
        CallLogAnalyzer callLogAnalyzer = new CallLogAnalyzer();
        List<CallSingleNumberStats> groupedByNumberTotalCallTimes = callLogAnalyzer
                .getGroupedByNumberTotalCallTimes(callLogs);
        
        for(CallSingleNumberStats stats : groupedByNumberTotalCallTimes){
            stats.setToTime(nowTimestamp);
            
            if(lastIntegrationTimestamp != null){
                stats.setFromTime(lastIntegrationTimestamp.longValue());
            } else {
                stats.setFromTime(null);
            }
        }
        
        return groupedByNumberTotalCallTimes;
    }
    
    /**
     * Wysyła dane przez API i zwraca informację czy integracja zakończyła się sukcesem
     * @param callLogStats lista statystyk w postaci akceptowanej przez API
     * @return true jeżeli integracja się powiodła, false w p.p.
     */
    private boolean sendAPIRequest(List<CallSingleNumberStats> callLogStats){
        CallsStatsHttpRequestWrapper requestWrapper = new CallsStatsHttpRequestWrapper(userId, callLogStats);
        NetworkManager networkManager = new NetworkManager();
        HttpResponseWrapper responseWrapper = null;
        
        try {
            LoggingUtil.d(this, "sending API request in calls stats integration...");
            responseWrapper = networkManager.sendAPIRequest(requestWrapper);
            LoggingUtil.d(this, "API request sent");
            
        } catch (NetworkException e) {
            LoggingUtil.e(this, "NetworkException occured while sending API request", e);
            return false;
        }
        
        return responseWrapper.isSuccessful();
    }
}
